extern screen_pixeles

%include "constantes.mac"

%define p_pantalla		 	[ebp - 4]
%define black			 	[ebp - 8]
%define white			 	[ebp - 12]

global smooth

section .rodata
ceros:	dd 0x0, 0x0, 0x0, 0x0

section .text

smooth:
	push ebp			; creo el marco de la pila
	mov ebp, esp			; creo el marco de la pila
	sub esp, 12			; reservo memoria en la pila
	
	push ebx			; salvo registros convencion C
	push edi			; salvo registros convencion C
	push esi			; salvo registros convencion C

	mov eax, [screen_pixeles]	; p_pantalla = screen_pixels
	mov p_pantalla, eax		; p_pantalla = screen_pixels

	mov ecx, ancho_pantalla_bytes	; inicializo indice del ciclo de filas
	shr ecx, 3			; inicializo indice del ciclo de filas
	sub ecx,100			; inicializo indice del ciclo de filas

	xor ebx, ebx			; contador filas totales

cicloFila:
	cmp ebx, 0
	je sigo
	mov eax, p_pantalla		 
	sub eax, ancho_pantalla_bytes	 
	movups xmm6, [eax]		; xmm6 = linea de px superior
sigo:
	mov eax, p_pantalla		
	movups xmm0, [eax]		; xmm0 = linea de px a modificar
	add eax, ancho_pantalla_bytes
	movups xmm7, [eax]		; xmm7 = linea de px inferior
	movaps xmm3, xmm0		; guardo referencia a xmm0
sumo_inf:	
	movaps xmm0, xmm7		; xmm0 => C(px) = inf(px)
unpackLinea:
	movaps xmm1, xmm0		
	punpcklbw xmm1, [ceros]		
	movaps xmm2, xmm0		
	punpckhbw xmm2, [ceros]		; tengo en xmm1 y xmm2 las words de xmm0
sumo_sup:
	jmp sumo_superior
	fin_sumo_superior:		; en xmm1 y xmm2 (bytes bajos y altos de xmm0) => C(px) = inf(px) + sup(px)

anterior: 
	jmp sumo_anterior		; sumo anterior agregando el pixel antes guardado
	fin_sumo_anterior:		; xmm1 y xmm2 => C(px) = ant(px) + inf(px) + sup(px) 

	jmp obtengo_pixel		; piso xmm5 con el nuevo pixel
	fin_obtengo_pixel:		; piso xmm5 con el nuevo pixel

siguiente:
	jmp sumo_siguiente
	fin_sumo_siguiente:		; xmm1 y xmm2 => C(px) = inf(px) + ant(px) + sup(px) + sgte(px)
	psrlw xmm1, 2			
	psrlw xmm2, 2			
	packuswb xmm1, xmm2		; divido por 4 bytes bajos(xmm1) y altos(xmm2) de xmm0
	movaps xmm0, xmm1
	mov esi, p_pantalla		
	movdqu [esi], xmm0		; cambio cada color de pixel original por el calculo

	jmp incremento_blancos_negros
	fin_incremento_blancos_negros:	; incremento blancos o negros

sgte_linea:
	mov eax, p_pantalla
	add eax, 12
	mov p_pantalla, eax		; muevo puntero 12 bytes

loop cicloFila

cambio_de_fila:
	inc ebx				; incremento contador de filas
	xor ecx, ecx			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	mov ecx, alto_pantalla_bytes	; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	shr ecx, 1			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	cmp ebx, ecx			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	je devuelvo_mayoria		; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla

	mov eax, [screen_pixeles]	; p_pantalla = screen_pixels
	mov p_pantalla, eax		; p_pantalla = screen_pixels

	mov eax, ancho_pantalla_bytes	; muevo a la siguiente fila de la pantalla
	mul ebx				; muevo a la siguiente fila de la pantalla
	add p_pantalla, eax		; muevo a la siguiente fila de la pantalla

	mov ecx, ancho_pantalla_bytes	; restauro cantidad iteraciones en la fila
	shr ecx, 3			; restauro cantidad iteraciones en la fila
	sub ecx,100			; restauro cantidad iteraciones en la fila

	xorps xmm5, xmm5		; no hay pixel anterior a la primer linea

	jmp cicloFila			; itero sobre la fila

sumo_superior:
	movaps xmm7, xmm6
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm6)
	punpckhbw xmm6, [ceros]		; xmm7 = 8W (de 8B altas de xmm6)
	paddw xmm1, xmm7		; sumo low words en xmm1
	paddw xmm2, xmm6		; sumo high words en xmm2
jmp fin_sumo_superior


sumo_anterior:
	movaps xmm4, xmm3		; shift de xmm0_original a izquierda
	pslldq xmm4, 3
	paddb xmm4, xmm5		; completo pixel (como se lo sumo a 0 no es necesario el unpck)

	movaps xmm7, xmm4
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm4)
	punpckhbw xmm4, [ceros]		; xmm4 = 8W (de 8B altas de xmm4)
	paddw xmm1, xmm7		; sumo lows 
	paddw xmm2, xmm4		; sumo highs
jmp fin_sumo_anterior

sumo_siguiente:				; paddusb xmm0, shr(xmm4)
	movaps xmm4, xmm3		; xmm4 = xmm0_original
	psrldq xmm4, 3	

	movaps xmm7, xmm4
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm4)
	punpckhbw xmm4, [ceros]		; xmm4 = 8W (de 8B altas de xmm4)
	paddw xmm1, xmm7		; sumo lows
	paddw xmm2, xmm4		; sumo highs
jmp fin_sumo_siguiente

incremento_blancos_negros:
	xor esi, esi
	movaps xmm4, xmm0
	punpcklbw xmm4, [ceros]
	movaps xmm1, xmm4		; xmm1 = 8W (de 8B bajas de xmm4)

	movaps xmm4, xmm0
	punpckhbw xmm4, [ceros]
	movaps xmm2, xmm4		; xmm2 = 8W (de 8B altos de xmm4)
sumo:
	pextrw edx, xmm1, 00000001b
	cmp edx, 0
	jne sumo_blancos1
	inc dword black			; contadorNegros++
	jmp sigo1
sumo_blancos1:
	inc dword white			; contadorBlancos++	
	sigo1:
	pextrw edx, xmm1, 00000010b
	cmp edx, 0
	jne sumo_blancos2
	inc dword black			; contadorNegros++
	jmp sigo2
sumo_blancos2:
	inc dword white			; contadorBlancos++	
	sigo2:
	pextrw edx, xmm1, 00000011b
	cmp edx, 0
	jne sumo_blancos3
	inc dword black			; contadorNegros++
	jmp sigo3
sumo_blancos3:
	inc dword white			; contadorBlancos++	
	sigo3:
	pextrw edx, xmm1, 00000100b
	cmp edx, 0
	jne sumo_blancos4
	inc dword black			; contadorNegros++
	jmp sigo4
sumo_blancos4:
	inc dword white			; contadorBlancos++	
	sigo4:
	pextrw edx, xmm1, 00000100b
	cmp edx, 0
	jne sumo_blancos5
	inc dword black			; contadorNegros++
	jmp sigo5
sumo_blancos5:
	inc dword white			; contadorBlancos++	
	sigo5:
	pextrw edx, xmm1, 00000101b
	cmp edx, 0
	jne sumo_blancos6
	inc dword black			; contadorNegros++
	jmp sigo6
sumo_blancos6:
	inc dword white			; contadorBlancos++	
	sigo6:
	pextrw edx, xmm1, 00000110b
	cmp edx, 0
	jne sumo_blancos7
	inc dword black			; contadorNegros++
	jmp sigo7
sumo_blancos7:
	inc dword white			; contadorBlancos++	
	sigo7:
	pextrw edx, xmm1, 00000111b
	cmp edx, 0
	jne sumo_blancos8
	inc dword black			; contadorNegros++
	jmp sigo8
sumo_blancos8:
	inc dword white			; contadorBlancos++	
	sigo8:
	cmp esi, 0
	jne fin_incremento_blancos_negros
	movaps xmm1, xmm2
	inc esi
	jmp sumo

obtengo_pixel:
	xor eax, eax			; obtengo mascara del ultimo pixel
	movaps xmm5, xmm3		; copia de xmm0 para la mascara del pixel
	mov eax, 0xFFFFFF00
	movd xmm7, eax
	pshufd xmm7, xmm7, 11001111b	; mascara en xmm7
	pand xmm5, xmm7			; obtengo el pixel
	psrldq xmm5, 9			; en xmm5 tengo los 3 bytes del ultimo pixel de la linea antes procesada
jmp fin_obtengo_pixel

devuelvo_mayoria:
	xor edx, edx
	xor edi, edi
	mov edi, dword white		; ecx = white
	mov edx, dword black		; edx = black
comparo:
	cmp edx, edi			; contadorNegros > contadorBlancos
	jg mayoria_negros

mayoria_blancos:
	xor eax, eax
	jmp final

mayoria_negros:
	xor eax, eax
	inc ax

final:
	pop esi		; desarmo el stack frame
	pop edi		; desarmo el stack frame
	pop ebx		; desarmo el stack frame
	add esp, 12 	; desarmo el stack frame
	pop ebp		; desarmo el stack frame
	ret
